<?php

require_once 'components/renderer.php';
require_once 'components/input_values.php';
require_once 'components/response.php';

interface IHandler
{
    /**
     * @abstract
     * @return string
     */
    function GetName();

    function ProcessInput(IPageInput $pageInput);
}

abstract class VerticalGridProcessorOperation
{
    /** @var \IResponseFactory|null */
    private $responseFactory;

    public function __construct(IResponseFactory $responseFactory = null)
    {
        $this->responseFactory = isset($responseFactory) ? $responseFactory : new XMLResponseFactory();
    }

    /**
     * @return IResponse
     */
    protected final function CreateResponse()
    {
        return $this->responseFactory->CreateResponse();
    }

    /**
     * @abstract
     * @param VerticalGrid $grid
     * @param IDataset $dataset
     * @param IPageInput $input
     * @param Renderer $renderer
     * @return IResponse
     */
    public abstract function ProcessInput(VerticalGrid $grid, IDataset $dataset, IPageInput $input, Renderer $renderer);

    /**
     * @abstract
     * @param IPageInput $input
     * @return boolean
     */
    public abstract function AcceptInput(IPageInput $input);
}

class UpdateGridOperation extends VerticalGridProcessorOperation
{
    /** @var string */
    private $subActionName;

    /** @var string[] */
    private $conditionFields;

    /**
     * @param string $subActionName
     * @param string[] $conditionFields
     */
    public function __construct($subActionName, $conditionFields)
    {
        parent::__construct();
        $this->subActionName = $subActionName;
        $this->conditionFields = $conditionFields;
    }

    public function ProcessInput(VerticalGrid $grid, IDataset $dataset, IPageInput $input, Renderer $renderer)
    {
        $fieldIndex = 0;
        foreach($this->conditionFields as $conditionField)
        {
            $value = $input->Get()->GetValue('pk' . $fieldIndex);
            $dataset->AddSimpleCondition($conditionField, ConditionOperator::$Equals, $value);
            $fieldIndex++;
        }

        $dataset->Open();
        $dataset->Next();

        $response = $this->CreateResponse();
        $response->SetResult(ResponseResult::$OK);

        $response->AddAsHtml('content', $grid->RenderGridContent($renderer));

        $dataset->Close();

        return $response;
    }

    public function AcceptInput(IPageInput $input)
    {
        return
            ($input->Get()->GetValue(OperationName::Action) == ActionOperation::Update) &&
            ($input->Get()->GetValue(OperationName::SubAction) == $this->subActionName);
    }
}

class CommitInsertOperation extends VerticalGridProcessorOperation
{
    public function __construct(IResponseFactory $responseFactory = null)
    {
        parent::__construct($responseFactory);
    }

    /**
     * @param IPageInput $input
     * @return boolean
     */
    public function AcceptInput(IPageInput $input)
    {
        return
            ($input->Get()->GetValue(OperationName::Action) == ActionOperation::Post) &&
            ($input->Get()->GetValue(OperationName::SubAction) == 'insert');
    }

    /**
     * @param VerticalGrid $grid
     * @param IDataset $dataset
     * @param IPageInput $input
     * @param Renderer $renderer
     * @return IResponse
     */
    public function ProcessInput(VerticalGrid $grid, IDataset $dataset, IPageInput $input, Renderer $renderer)
    {
        $response = $this->CreateResponse();
        
        $dataset->Open();

        $dataset->Insert();
        $grid->ProcessPost($input->Post());
        $dataset->Post();

        $dataset->Close();

        $response->SetResult(ResponseResult::$OK);
        return $response;
    }
}

class CommitUpdateOperation extends VerticalGridProcessorOperation
{
    /**
     * @param IPageInput $input
     * @return boolean
     */
    public function AcceptInput(IPageInput $input)
    {
        return
            ($input->Get()->GetValue(OperationName::Action) == ActionOperation::Post) &&
            ($input->Get()->GetValue(OperationName::SubAction) == 'update');
    }

    public function ProcessInput(VerticalGrid $grid, IDataset $dataset, IPageInput $input, Renderer $renderer)
    {
        $response = $this->CreateResponse();

        $primaryKeyValues = $grid->ExtractPrimaryKeyValuesFromPost($input->Post());

        foreach($primaryKeyValues as $fieldName => $value)
            $dataset->AddSimpleCondition($fieldName, ConditionOperator::$Equals, $value);

        $dataset->Open();
        $dataset->Next();
        $dataset->Edit();
        $grid->ProcessPost($input->Post());
        $dataset->Post();
        $dataset->Close();

        $response->SetResult(ResponseResult::$OK);
        return $response;
    }
}

abstract class VerticalGridProcessor implements IHandler
{
    /** @var string */
    private $name;

    /** @var boolean */
    private $isCreated;

    /** @var null|VerticalGrid */
    private $verticalGrid;

    /** @var null|EditableDataset */
    private $dataset;

    /** @var VerticalGridProcessorOperation[] */
    private $operations;

    /** @var \Renderer */
    private $renderer;

    public function __construct($name, Renderer $renderer)
    {
        $this->name = $name;
        $this->isCreated = false;
        $this->verticalGrid = null;
        $this->dataset = null;
        $this->operations = array();
        $this->renderer = $renderer;
    }

    public final function AddOperation(VerticalGridProcessorOperation $operation)
    {
        $this->operations[] = $operation;
    }

    /**
     * @param IPageInput $pageInput
     * @return IResponse
     */
    public final function ProcessInput(IPageInput $pageInput)
    {
        foreach($this->operations as $operation)
            if ($operation->AcceptInput($pageInput))
            {
                if (!$this->IsCreated())
                    $this->CreateComponent();
                $response = $operation->ProcessInput($this->verticalGrid, $this->dataset, $pageInput, $this->renderer);
                return $response;
                break;
            }
    }

    public final function DisplayGrid()
    {
        if (!$this->IsCreated())
            $this->CreateComponent();
        $this->dataset->Open();
        $this->dataset->Next();
        echo $this->verticalGrid->RenderFullGrid($this->renderer);
        $this->dataset->Close();
    }

    private final function CreateDataset()
    {
        $this->dataset = $this->DoCreateDataset();
    }

    private final function CreateComponent()
    {
        $this->CreateDataset();
        $this->verticalGrid = $this->DoCreateComponent();
        $this->isCreated = true;
    }

    /**
     * @abstract
     * @return VerticalGrid
     */
    protected abstract function DoCreateComponent();

    /**
     * @abstract
     * @return IDataset
     */
    protected abstract function DoCreateDataset();

    /**
     * @return null|VerticalGrid
     */
    public final function GetVerticalGrid()
    {
        return $this->verticalGrid;
    }

    public final function GetDataset()
    {
        return $this->dataset;
    }

    public final function GetName()
    {
        return $this->name;
    }

    /**
     * @return boolean
     */
    public final function IsCreated()
    {
        return $this->isCreated;
    }
}

?>